<?php
/*********************************************
 *  CPG Dragonfly™ CMS
 *********************************************
	Copyright © since 2010 by CPG-Nuke Dev Team
	http://dragonflycms.org

	Dragonfly is released under the terms and conditions
	of the GNU GPL version 2 or any later version
*/

namespace Poodle;

abstract class Input extends \ArrayIterator
{
	public static function fixEOL($str, $eol="\n") { return preg_replace('#\r\n|\r|\n#', $eol, $str); }

	public static function fixSpaces($str) { return preg_replace('#\p{Zs}#u', ' ', $str); }

	/**
	 * http://tools.ietf.org/html/rfc5321#section-4.1.2
	 * While the definition for Local-part is relatively permissive, for
	 * maximum interoperability, a host that expects to receive mail SHOULD
	 * avoid defining mailboxes where the Local-part requires (or uses) the
	 * Quoted-string form or where the Local-part is case-sensitive.
	 */
	public static function lcEmail($str)
	{
		return mb_strtolower(trim($str));
	}

	public static function asDate($v)
	{
		if (preg_match('#^([0-9]{4}-0[1-9]|1[0-2]-(0[1-9]|[12][0-9]|3[01]))#', $v, $m)) {
			return new \Poodle\Date($m[1], 'UTC');
		}
		return null;
	}

	public static function asDateFromMonth($v)
	{
		if (preg_match('#^([0-9]{4}-0[1-9]|1[0-2])#', $v, $m)) {
			return new \Poodle\Date($m[1], 'UTC');
		}
		return null;
	}

	public static function asDateFromWeek($v)
	{
		if (preg_match('#^([0-9]{4}-W([0-4][0-9]|5[0-3]))#', $v, $m)) {
			return new \Poodle\Date($m[1], 'UTC');
		}
		return null;
	}

	// $local=true uses current date_default_timezone
	public static function asDateTime($v, $local=false)
	{
		if (preg_match('#^([0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])[T ]([01][0-9]|2[0-3]):[0-5][0-9](:([0-5][0-9]|60))?)#', $v, $m)) {
			return new \Poodle\DateTime($m[1], $local?null:'UTC');
		}
		return null;
	}

	public static function asTime($v)
	{
		if (preg_match('#(([01][0-9]|2[0-3]):[0-5][0-9](:([0-5][0-9]|60)(\\.[0-9]+)?)?)#', $v, $m)) {
			return new \Poodle\Time('1970-01-01 '.$m[1], 'UTC');
		}
		return null;
	}

	public static function str2float($value, $def=null)
	{
		if (preg_match('#-?[0-9]+(\\.[0-9]+)?$#D', $value)) { return (float)$value; }
		return $def;
	}

	public static function strip($value, $def='')
	{
		if (!is_string($value)) { return $value; }
		$value = self::fixEOL(trim(self::fixSpaces(strip_tags($value))));
		return (!strlen($value) ? $def : $value);
	}

	public static function validateEmail($v) { return Dragonfly_Net_Validate::emailaddress($v); }

	public static function validateURI($v)   { return Dragonfly_Net_Validate::uri($v); }

	private static
		$js_regex    = array(
			'#<(/?script[^>]*)>#is' => '&lt;$1&gt;',
			'#([^w](on|data)[a-z]+)\s*=#is' => '$1&#61;',
		),
		$html_regex = array(
			'#<\s*(/)?\s*#' => '<$1',
			'#(</?[a-zA-Z0-1]+)#e' => 'strtolower(\'$1\')', # don't match whole tag (</?[a-zA-Z]+)([^>]*>) or PHP adds slashes
			'#<head>.*?<\/head>#' => '',
			'#<\/?(html|head|body|link|meta)( [^>]*)?>#' => '',
			'#\s+(xmlns="|class="apple|_moz_dirty=")[^"]*"#' => '', # WebKit/Gecko
			'#\s*(font-family:[^;]*;|<title>[^<]*<\/title>|align="[^"]*")#' => '', # OpenOffice
			# MS Word
			'#<!--\[(((?!-->).)*)\]-->#s' => '',
			'#</?(xml|[ovwxp]:\w+)[^>]*>#si' => '',
			'#mso-[^;]+;#si' => '',
			'#\s+class="Mso[a-z]+"#si' => '',
			# Obsolete HTML
			'#(</?)font#' => '$1span',
			'#text-decoration:\s*underline;#' => '',
			# IE
			// issue with this line, it's not 100% working
//			'#<([^>]+)>#e' => 'preg_replace(\'#(\s[a-z-]+)\s*=\s*([^"\\\'\s>]+)#i\', \'\\$1="\\$2"\', str_replace("\\\'","\'","<$1>"))',
			'#"[\t ]*([^"=\r\n><]+)[\t ]*"#' => '"$1"',
			'@<([^>]+)color="(#[A-F0-9]+)"@i' => '<$1style="color:$2;"',
			'@<([^>]+)background-color="(#[A-F0-9]+)"@' => '<$1style="background-color:$2;"',
			# HTML 5 compatibility
			'#(</?)acronym#' => '$1abbr',
			# deprecated/obsolete in XHTML & HTML 5:
			'#</?(basefont|big|center|dir|frame|frameset|noframes|s|strike|tt|u|xmp)[^a-z][^>]+>#' => '',
			# cleanup:
			'#style="\s*"#i' => '',
			'#<(area|base|br|col|hr|img|input|param)([^>]*)/?>#i' => '<$1$2/>',
//			'#<br[^>]+>(\s*</?([uo]l|p|div|code|samp|pre|li))#' => '$1',
			'#\s*/+\s*>#' => '/>',
		);

	public static function xml_entity_decode($string, $quote_style=ENT_NOQUOTES, $charset=\Poodle::CHARSET)
	{
		// replace numeric entities
		$string = preg_replace('~&#x([0-9a-f]+);~ei', 'chr(hexdec("\\1"))', $string);
		$string = preg_replace('~&#([0-9]+);~e', 'chr("\\1")', $string);
		// replace literal entities
		if (version_compare(phpversion(), '5.3.4', '<')) {
			$entities = array();
			$entlatin = get_html_translation_table(HTML_ENTITIES, $quote_style);
			foreach ($entlatin as $char => $ent) {
				$entities[utf8_encode($char)] = $ent;
			}
		} else {
			$entities = get_html_translation_table(HTML_ENTITIES, $quote_style, $charset);
		}
		if (!$entities) {
			throw new \Exception("get_html_translation_table(HTML_ENTITIES, $quote_style, $charset) is broken!");
		}
		unset($entities['&'],$entities['<'],$entities['>']);
		$entities = array_flip($entities);
		return strtr($string, $entities);
	}

	# With this function we
	# - destroy scripts for XSS prevention
	# - replace NO-BREAK and other types of utf-8 spacings
	# - repair XHTML
	public static function fixHTML($value, $def='')
	{
		if (!is_string($value)) { return $value; }
		$value = trim(self::fixSpaces(self::xml_entity_decode($value)));
		if (!strlen($value)) { return $def; }
		# repair XHTML stage 1
		$value = preg_replace(array_keys(self::$html_regex), array_values(self::$html_regex), $value);
		if (!POODLE_BACKEND) {
			$value = preg_replace(array_keys(self::$js_regex), array_values(self::$js_regex), $value);
		}
		# repair XHTML stage 2, buggy: puts line-endings where we don't want them
//		if (function_exists('tidy_repair_string')) { $value = tidy_repair_string($value, array('output-xhtml'=>1,'show-body-only'=>1,'newline'=>'LF'), POODLE_CHARSET); }

		# repair uri's
		$c = 0;
		do {
			$value = preg_replace('#(<[^>]+(href|src|action)=["\'][^"\']+)/[^\'"/]+/\\.\\./#', '$1/', $value, -1, $c);
		} while ($c);
//		$value = preg_replace('#(<[^>]+(href|src|action))="([a-z][a-z0-9\\+\\.\\-]+://'.\Poodle\URI::host().')?'.\Poodle::$URI_BASE.'/#', '$1="/', $value);

		return self::fixEOL(trim($value));
	}
/*
	protected function a2c($v)
	{
		$c = get_class($this);
		return is_array($v) ? new $c($v) : $v;
	}
	public function offsetGet($i) { return $this->a2c(parent::offsetGet($i)); }
	public function current() { return $this->a2c(parent::current()); }
*/
}
